﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////


#pragma once

#include "ICADDimension.h"
#include "Matrix4d.h"

namespace gcmp
{
    class IModelView;
    class IElement;
    class IGraphicsNodePath;
    class ICADDimension;
    class IHatchSettings;
    class IGraphicsStyleData;
    class IGraphicsNode;
    class IPlane;
    class ICurve2d;
    class Box2d;
    class Vector2d;
    class ILinkDocumentElement;
    class IDrawingViewport;

    ///构件导出模式
    enum ExportMode
    {
        NO_EXPORT,              ///不导出
        CUSTOM_EXPORT,          ///自定义导出
        HLR_BODY,               ///体消隐，线直接导出
        HLR_BODY_CURVE,         ///体和线都消隐
        HLR_RETREAT,            ///遮挡退让
        ONLY_CURVE,             ///只导出线，忽略体
        DIRECT_EXPORT,          ///单独导出（体自身消隐）
        HLR_MASKING,            ///遮盖住其它所有消隐对象,当前需求是GAP的遮罩和填充（勾选“屏蔽构件”）
        HLR_MASKING_BY_ORDER,   ///与遮罩对象（HLR_MASKING）按绘制顺序进行遮挡,当前需求是GAP的填充（未勾选“屏蔽构件”）
        HLR_RETREAT_RETAIN_LINE,///遮挡退让，保留辅助线（辅助线不参与自消隐）
        ONLY_CURVE_AND_EDGE,    ///只导出线和三维体上的边（使用场景如视图为线框模式的时候）(已废弃)
        HLR_BODY_CURVE_TEXT,    ///体、线、文本（单行文本和富文本）消隐，文本消隐仅是判断自身的可见性，不会遮挡体、线
    };

    ///导出构件节点类型
    enum ExportNodeType
    {
        ExportNode_UNKNOWN,            ///未知
        ExportNode_CURVE,              ///线
        ExportNode_REGION,             ///填充
        ExportNode_TEXT,               ///文字
        ExportNode_RICHTEXT,           ///富文本
        ExportNode_DIMENSION,          ///标注
    };

    ///导出节点参数
    struct ExportNodeParameter
    {
        ExportNodeType type;
        bool bSection;
        bool bHidden;

        ExportNodeParameter(ExportNodeType t, bool s, bool h) : type(t), bSection(s), bHidden(h) {}
    };

    /// \brief 导出节点参数
    struct CurveAndParameter
    {
        const IElement* pElement;               ///< 构件
        const IGraphicsNode* pGCurveNode;       ///< 节点
        const IGraphicsNodePath* pGPath;        ///< 节点路径
        const IGraphicsStyleData* pGStyleData;  ///< 节点样式
        const ICurve2d* pGCurve2d;              ///< 二维投影线
        bool bSection;                          ///< 是否为截面线
        bool bHidden;                           ///< 是否为隐藏线

        CurveAndParameter(const IElement* pSrcElement
            , const IGraphicsNode* pNodeCurve
            , const IGraphicsNodePath* pPath
            , const IGraphicsStyleData* pStyleData
            , const ICurve2d* pCurve2d
            , bool section, bool hidden)
            : pElement(pSrcElement)
            , pGCurveNode(pNodeCurve)
            , pGPath(pPath)
            , pGStyleData(pStyleData)
            , pGCurve2d(pCurve2d)
            , bSection(section)
            , bHidden(hidden)
        {
        }
    };

    ///导出遮挡退让类型
    enum ExportRetreatType
    {
        EXPORT_IGNORE,              ///不处理
        EXPORT_HIDE,                ///遮挡不退让-支持填充参与
        EXPORT_RETREAT,             ///直接退让
        EXPORT_HEIGHT_RETREAT,      ///根据高度退让-支持填充参与
        EXPORT_LENGTH_RETREAT,      ///根据长度退让
        EXPORT_HOLLOW_RETREAT,      ///直接退让(中空)
    };

    // 块的插入点位置类型;
    enum BlockInsertPointType
    {
        WorldOrigin = 0,            // 世界坐标系的原点;
        LeftBottom,                 // 包围盒的左下角;
        LeftTop,                    // 包围盒的左上角;
        RightTop,                   // 包围盒的右上角;
        RightBottom,                // 包围盒的右下角;
        Center,                     // 包围的中心;
        UserDefine,                 // 指定插入点;
    };

    /// 导出数据元素
    struct ExportSourceData
    {
        const IElement* pElement;
        const IGraphicsNode* pGNode;
        const IGraphicsNodePath* pNodePath;
        const IGraphicsStyleData* pStyleData;
        ExportSourceData(const IElement* pSrcElement, const IGraphicsNode* pSrcGNode, const IGraphicsNodePath* pSrcNodePath, const IGraphicsStyleData* pStyle)
            : pElement(pSrcElement)
            , pGNode(pSrcGNode)
            , pNodePath(pSrcNodePath)
            , pStyleData(pStyle)
        {
        }
    };

    /// \brief 链接模型导出的消隐模式
    enum class LinkDocumentHLRMode : int32_t
    {
        SameProfessional = 0,///< 本专业消隐，其他专业消隐（相当于消隐两次）
        AllProfessional = 1,  ///< 所有专业统一消隐（相当于消隐一次）
    };

    // 参照实体基类;
    class IExportBlockEntity
    {
    public:
        virtual ~IExportBlockEntity() {}
    };

    // 参照实体element;
    class ExportBlockElement : public IExportBlockEntity
    {
    public:
        ExportBlockElement() :pElement(nullptr) {}
        const IElement* pElement;
    };
    // 参照本身;
    class ExportBlockReference : public IExportBlockEntity
    {
    public:
        ExportBlockReference() {}
        Matrix4d matrix;        // 到基准块的变换矩阵;
        std::wstring sName;
        std::wstring sLayerName;
        gcmp::BlockInsertPointType insertPointType;
        gcmp::Vector3d insertPoint;
        const IElement* pElement = nullptr; // 此块引用对应的实际Element（而ExportBlockElement::pElement是块定义对应的Element）
                                            // 例如 编组对象成块，那么指向的就是组对象，而不是组内的对象
                                            // 而entitys中才是组内的Element对象的集合
        std::vector<gcmp::OwnerPtr<IExportBlockEntity>> entitys;
    };
    
    typedef std::vector<gcmp::OwnerPtr<ExportBlockReference>> ExportBlock;          // 一组参照;

    ///自定义导出方法
    class IExportCustomizer
    {
    public:
        virtual ~IExportCustomizer() {}

        /*!
        *@brief      获取构件导出模式
        *@param[in]  pElement 构件
        *@param[in]  pModelView  模型视图
        *@return ExportMode 构件导出模式
        */
        virtual ExportMode GetExportMode(const IElement* pElement, IModelView* pModelView) const = 0;

        /*!
        *@brief      获取构件导出块，块内可以嵌套块，比如返回 aaa/bbb/ccc，则aaa内嵌套bbb，bbb内嵌套ccc;没有嵌套则直接返回块名;
        *@param[in]  pElement 构件
        *@param[in]  pModelView  模型视图
        *@param[out] strLayerName  块所属图层名，为空则不设置
        *@param[in,out] gcmp::BlockInsertPointType&  该块插入点的位置枚举类型
        *@param[in,out] gcmp::Vector3d&  当插入点的位置枚举类型为UserDefine的时候使用insertPoint作为插入点;
        *@return std::wstring 块名称，为空表示不成块
        */
        GCMP_OBSOLETE_API(2023 / 7 / 4, std::wstring GetExportBlock(const IElement* pElement, IModelView* pModelView, const IDrawingViewport* pViewport, std::wstring& strLayerName,
            gcmp::BlockInsertPointType& insertPointType, gcmp::Vector3d& insertPoint))
        virtual std::wstring GetExportBlock(const IElement* pElement, IModelView* pModelView,  std::wstring& strLayerName,
            gcmp::BlockInsertPointType& insertPointType, gcmp::Vector3d& insertPoint) const { return L""; }

        /*!
        *@brief      获取构件导出块，块内可以嵌套块，比如返回 aaa/bbb/ccc，则aaa内嵌套bbb，bbb内嵌套ccc;没有嵌套则直接返回块名;
        *@param[in]  pElement 构件
        *@param[in]  pModelView  模型视图
        *@param[in]  pViewport   视口
        *@param[out] strLayerName  块所属图层名，为空则不设置
        *@param[in,out] gcmp::BlockInsertPointType&  该块插入点的位置枚举类型
        *@param[in,out] gcmp::Vector3d&  当插入点的位置枚举类型为UserDefine的时候使用insertPoint作为插入点;
        *@return std::wstring 块名称，为空表示不成块
        */
        virtual std::wstring GetExportBlock(const IElement* pElement, IModelView* pModelView, const IDrawingViewport* pViewport, std::wstring& strLayerName,
            gcmp::BlockInsertPointType& insertPointType, gcmp::Vector3d& insertPoint) const = 0;
        
        /*!
        *@brief     获取导出的块和参照信息，可以嵌套;
        *@param[in] pModelView  模型视图
        *@param[in] std::set<const IElement*>& exportElements,可见的elements
        *@param[in] std::vector<ExportBlock>& exportBlocks, 所有的块参照信息;
        */
        virtual void GetExportBlock(IModelView* pModelView, std::set<const IElement*>& exportElements, std::vector<ExportBlock>& exportBlocks)const = 0;

        /*!
        *@brief      获取构件导出图层
        *@param[in]  pElement 构件
        *@param[in]  pModelView  模型视图
        *@param[in]  pPath    节点路径
        *@param[in]  ExportNodeParameter     节点类型参数
        *@return std::wstring 图层名称，为空表示不设置图层
        */
        virtual std::wstring GetExportLayer(const IElement* pElement, IModelView* pModelView, const IGraphicsNodePath* pPath, const ExportNodeParameter& paramter) const = 0;

        /*!
        *@brief      获取构件导出文字样式
        *@param[in]  pElement 构件
        *@param[in]  pPath    节点路径
        *@return std::wstring 文字样式，为空表示不设置样式
        */
        GCMP_OBSOLETE_API(2022 / 12 / 08, IExportCustomizer::GetTextStyle(const IElement* pElement, IModelView* pModelView, const IGraphicsNodePath* pPath))
            virtual std::wstring GetTextStyle(const IElement* pElement, const IGraphicsNodePath* pPath) const { return L""; };

        /*!
        *@brief      获取构件导出文字样式
        *@param[in]  pElement 构件
        *@param[in]  pModelView 模型视图
        *@param[in]  pPath    节点路径
        *@return std::wstring 文字样式，为空表示不设置样式
        */
        virtual std::wstring GetTextStyle(const IElement* pElement, IModelView* pModelView, const IGraphicsNodePath* pPath) const = 0;

        /*!
        *@brief      获取导出遮挡退让类型
        *@param[in]  lowElementData     低程构件
        *@param[in]  highElementData    高程构件
        *@param[in]  pModelView      模型视图
        *@return ExportRetreatType 遮挡退让类型
        */
        virtual ExportRetreatType GetExportRetreatType(const ExportSourceData& lowElementData, const ExportSourceData& highElementData, IModelView* pModelView) const = 0;

        /*!
        *@brief      获取构件导出填充样式
        *@param[in]  pElement 构件
        *@param[in]  pModelView  模型视图
        *@param[in]  pPath    节点路径
        *@param[in]  pStyleData    节点样式
        *@param[in]  bSection      是否截面
        *@return IHatchSettings 填充样式，为空表示采用节点自带的Style
        */
        virtual OwnerPtr<IHatchSettings> GetHatchSetting(const IElement* pElement, IModelView* pModelView, const IGraphicsNodePath* pPath, const IGraphicsStyleData* pStyleData, bool bSection) const = 0;

        /*!
        *@brief      获取构件导出标注
        *@param[in]  pElement 构件
        *@param[in]  pModelView  模型视图
        *@return std::vector<OwnerPtr<ICADDimension>> 导出标注数据集
        */
        virtual std::vector<OwnerPtr<ICADDimension>> GetExportDimensions(const IElement* pElement, IModelView* pModelView) const = 0;

        /*!
        *@brief      获取遮罩填充遮挡优先级列表
        *@param[in]  pModelView  模型视图
        *@return std::vector<ElementId> 遮罩填充遮挡优先级列表，顺序靠前的被靠后的遮挡
        */
        virtual std::vector<gcmp::ElementId> GetMaskOrderFromBtmToTop(IModelView* pModelView) const = 0;

        /*!
        *@brief      是否导出多段线
        *@param[in]  pElement 构件
        *@param[in]  pModelView  模型视图
        *@param[out]  setRelatedId  关联的需要合并多段线的构件
        *@return bool 是否导出多段线
        */
        virtual bool IsExportPolyLine(const IElement* pElement, IModelView* pModelView, std::set<ElementId>& setRelatedId) const = 0;

        /*!
        *@brief      获取多段线数组
        *@param[in]  pElement 构件
        *@param[in]  pModelView  模型视图
        *@param[in]  curveAndParams  线和参数
        *@return std::vector<std::vector<int>> 线Ids
        */
        virtual std::vector<std::vector<int>> GetExportPolyLines(IModelView* pModelView, const std::vector<CurveAndParameter>& curveAndParams) const = 0;

        /*!
        *@brief      获取线的像素宽度
        *@param[in]  pElement 构件
        *@param[in]  pModelView 模型视图
        *@return int 线宽像素值 
        */
        virtual int GetLineWidthPixelMode(const IElement* pElement, const IGraphicsNode* pGraphicsNode, IModelView* pModelView) const = 0;

        /*!
        *@brief      获取图纸中不同视图对象的导出隐藏线的模式
        *@param[out] bExportHiddenLine   导出隐藏线
        *@param[out] KeepHighHiddenLine  隐藏线保留高程
        *@param[in]  pMainView  视口(图纸)对象
        *@param[in]  pSubView   子视图对象
        */
        virtual void GetExportHiddenLineModeInViewport(bool& bExportHiddenLine, bool& bKeepHighHiddenLine, const IModelView* pMainView, const IModelView* pSubView) const = 0;

        /*!
        *@brief      颜色是否随视图
        *@param[in]  pModelView  模型视图
        *@param[in]  pLinkDocument  链接文档
        *@param[out] bool 是否随视图
        */
        virtual void GetExportColorByView(const IModelView* pModeView, const ILinkDocumentElement* pLinkDocument, bool& byView) const = 0;

        /*!
        *@brief      线样式是否随视图
        *@param[in]  pModelView  模型视图
        *@param[in]  pLinkDocument  链接文档
        *@param[out] bool 是否随视图
        */
        virtual void GetExportLineStyleByView(const IModelView* pModeView, const ILinkDocumentElement* pLinkDocument, bool& byView) const = 0;

        /*!
        *@brief      获取链接模型导出的消隐模式
        *@param[in]  pModelView  模型视图
        *@return LinkDocumentHLRMode 消隐模式
        */
        virtual LinkDocumentHLRMode GetLinkDocumentHLRMode(IModelView* pModelView) const = 0;

        /*!
        *@brief      合并导出时计算每一个视图的插入点
        *@param[out] insertPoint 计算得到的当前视图的插入点        
        *@param[in]  pModelView 当前视图对象
        *@param[in]  box   当前视图的包围盒大小
        *@param[in]  index 当前视图的索引
        *@param[in]  nTotal 合并导出的视图总数
        *@return     true-产品定制了插入点 false-采用平台默认的实现
        */
        virtual bool GetInsertPoint(Vector2d& insertPoint, const IModelView* pModelView, const Box2d& box, int index, int nTotal) = 0;

        /*!
        *@brief      获取构件导出标注中的标记
        *@param[in]  pElement 构件
        *@param[in]  pModelView  模型视图
        *@param[in]  gNodePaths  标注中节点路径
        *@return std::vector<unsigned int> 导出标注中的标记索引
        */
        virtual std::vector<unsigned int> GetExportDimensionAttachMarkers(const IElement* pElement, IModelView* pModelView, const std::vector<const IGraphicsNodePath*>& gNodePaths) const = 0;
        
        /*!
        *@brief      定制化element的导出数据;
        *@param[in]  const IModelView*  模型视图
        *@param[in]  const IElement* 构件
        *@param[in]  const IGraphicsElementShape* 构件的可见的ElementShape
        *@param[out]  OwnerPtr<IGraphicsElementShape>& opNewElementShape  定制的Element的新的Grep
        *@return bool 返回true，表示定制；返回false，表示不定制，按原来的方式导出;
        */
        virtual bool CustomizeElementExportData(const IModelView* pModelView, const IElement* pElement, const IGraphicsElementShape* pElementShape, OwnerPtr<IGraphicsElementShape>& opNewElementShape) const = 0;

        /*!
        *@brief      获取富文本格式字符串中行距导出到CAD中的替换值
        *@param[in]  old  待替换的旧值
        *@return double 返回替换新值，如果返回值小于0（比如-1）则不会发生替换
        */
        virtual double GetRichTextReplacedLineSpace(double old) const = 0;

        /*!
        *@brief      定制化隐藏线导出
        *@param[out] std::vector<OwnerPtr<ICurve2d*>>   返回新的隐藏线
        *@param[in]  const IModelView*                  pHiddenLine所属的模型视图
        *@param[in]  const IElement* pElement           pHiddenLine所属的Elemnt
        *@param[in]  const ICurve2d* pHiddenLine        原隐藏线
        *@return bool 返回true，表示定制；返回false，表示不定制，导出原隐藏线
        */
        virtual bool GetReplacedHiddenLines(std::vector<OwnerPtr<ICurve2d>>& vecNewCurve2d, const IModelView* pModelView, const IElement* pElement, const ICurve2d* pHiddenLine) const
        {
            return false;
        }

        /*!
        *@brief      获取element集合的绘图次序
        *@param[in]  const IModelView* pModelView                      模型视图
        *@param[in]  const std::vector<const IElement*>& elements      element集合
        *@param[out]  std::vector<const IElement*>& topElements        前置显示的Element集合，索引为0的元素置于显示的最顶层
        *@param[out]  std::vector<const IElement*>& bottomElements     后置显示的Element集合，数组的最后一个元素的置于显示的最底层
        *@return void
        */
        virtual void GetDrawOrder(const IModelView* pModelView, const std::vector<const IElement*>& elements, std::vector<const IElement*>& topElements, std::vector<const IElement*>& bottomElements) const
        {            
            return;
        }

        /*!
        *@brief      获取导出到CAD中的属性线宽值（非全局线宽）
        *@param[out] nCADLineWidth                      导出到dwg中属性线宽值
        *@param[in]  nPixelLineWidth                    像素线宽值
        *@return bool 返回true，表示输出参数nCADLineWidth有效；返回false，表示输出参数nCADLineWidth无效，而是使用内部映射关系
        */
        virtual bool GetLineWidth(LineWidth& nCADLineWidth, int nPixelLineWidth) const
        {
            return false;
        }

        /*!
        *@brief      获取导出到CAD中的打印线宽值（非全局线宽）
        *@param[in]const IModelView* pModelView               模型视图
        *@param[in]const IElement* pElement                   构件
        *@param[in]IGraphicsNodePath* IGraphicsNodePath       节点路径
        *@param[in]  dPrintLineWidth                          打印线宽值
        *@param[out] nCADLineWidth                            导出到dwg中属性线宽值
        *@return bool 返回true，表示输出参数nCADLineWidth有效；返回false，表示输出参数nCADLineWidth无效，此时使用GCMP内部定义的映射关系
        */
        virtual bool GetExportLineWidth(const IModelView* pModelView, const IElement* pElement, const IGraphicsNodePath* pGraphicsNodePath, double dPrintLineWidth, LineWidth& nCADLineWidth) const
        {
            return false;
        }
    };
}